// 解决小程序  实例 组件 混入问题
// 基本思路与用法  参考vue
/* 
  1. 修改合并机制，改为深度合并
  2. 在全局混入 computed 计算机制
  date:  2020/4/48
  整合 computed 到全局 mixins函数
  2021/04/09 更新: 
  3.  深度混入  
  描述： 完成 page A混入 B， B又混入 c ... 等这种多层级混入的机制
  2021/04/24 更新: 
  4.  组件混入功能开启  同时组件混入  computed 计算属性  方法同Page构造器一样   
  2021/09/17
  5.混入页面或者组件实例-方法  两者互相兼容  ###  定义方法( 页面方法定义在根对象上,组件定义在methods里 )

  */


const comUtils = require("../../utils/common");
const computedConfig = require('../computed/config');
const mixinConfig = require('./config');

 // 页面混入
 const lifecycle_Page = ['onLoad', 'onReady', 'onShow', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage', 'onPageScroll'];

// 递归收集 mixin
 function getDeepMixins( mixConfig , deepArr ) {
  const c_mixins = mixConfig.mixins;
  if (comUtils.isType(c_mixins, 'Array') && c_mixins.length != 0) {
    deepArr.push(...c_mixins);
    c_mixins.forEach(c_mixs_config => {
      getDeepMixins(c_mixs_config , deepArr);
    });
  }
  return deepArr
}
const nativePage = Page;
 Page =  function (config) {
    // 全局混入开启关闭
 if( mixinConfig.openGlobalMixin_page ){ 
  let mixinsDeep = [];
   //收集子 mixin
   mixinsDeep = getDeepMixins( config , mixinsDeep )
   //加入全局mixin
   if (mixinConfig.globalMixins_page) {
     mixinsDeep.unshift(mixinConfig.globalMixins_page);
   }
   _mixin_extend(mixinsDeep, config);
 }
   
   nativePage(config);
 }

 
 
 
 // 组件混入
 const lifecycle_Component = ["created", "attached", "ready", "moved", "detached", "error"];
 
// 组件全局  mixins computed

 const nativeComponent = Component;
 Component = function (config) {
   if( mixinConfig.openGlobalMixin_component ){
    let mixinsDeep = [];
    // 收集子 mixin
    mixinsDeep = getDeepMixins(config , mixinsDeep);
    // 加入全局mixin
    if (mixinConfig.globalMixins_component) {
      mixinsDeep.unshift(mixinConfig.globalMixins_component);
    }
    _mixin_extend(mixinsDeep, config, false);
    const computedData = config[computedConfig.computedKey_page];
    if (computedData && comUtils.isType(computedData, "Object")) {
      const { data } = config;
      data[computedConfig.computedKey_component] = computedData;
    }
   }
   nativeComponent(config);
 }
 
 /* 
  合并函数  
   对特殊属性  data computed 进行深度合并  
   对生命周期函数 onload onReady  合并在当前路由生命周期内
   对自定义方法  进行浅合并
   _mixin_extend(mixins:Object,config:Object , isPage:Boolean);
 */
 //页面 组件  共有合并关键字
 const public_mergeKeys = [
   "data"
   , computedConfig.computedKey_page
 ];
 //组件合并关键字
 const component_mergeKeys = [
   "behaviors"
   , "properties"
   , "lifetimes"
   , "methods"
   , "options"
 ];
// 针对 对象 或者 数组的合并
 function _mixin_merge(config , mixin ,  key){
  if (config[key] === undefined) {
    config[key] = mixin[key];
  } else {
    comUtils.merge(config[key], mixin[key]);
  }
 }
 // 继承
 function _mixin_extend(mixins, config, isPage = true) {
   let _lifecycle;
   if (isPage) {
     _lifecycle = lifecycle_Page;
   } else {
     _lifecycle = lifecycle_Component;
   }
   mixins.forEach(mixin => {
     if (comUtils.isType(mixin, 'Object')) {
       Object.keys(mixin).forEach(key => {
         //合并 页面或者 组件 data, computed
         if (public_mergeKeys.includes(key)) {
           _mixin_merge( config , mixin, key);
           //合并 页面或者 组件 生命周期
         } else if (_lifecycle.includes(key)) {
           let nativeLifecycle = config[key];
           if (nativeLifecycle) {
             config[key] = function () {
               let arg = Array.prototype.slice.call(arguments);
               mixin[key].apply(this, arg);
               return nativeLifecycle && nativeLifecycle.apply(this, arg);
             }
           } else {
             config[key] = mixin[key];
           }
           /* 页面 或者 组件 方法混入 */
         } else {
           // 页面方法混入
           if (isPage) {
             //排除组件关键字于生命周期
             if (!lifecycle_Component.includes(key)) {
               if (config[key] === undefined) {
                 if (key !== "methods") {
                   config[key] = mixin[key];
                 } else {
                   //对组件实例methods进行方法合并
                   if( comUtils.isType(mixin[key], "Object") ){
                     comUtils.merge( config , mixin[key] );
                   }
                 }
               }
             }
 
           } else {
             // 组件方法混入
             if (component_mergeKeys.includes(key)) {
               _mixin_merge( config , mixin , key);
             } else {
               // 排除页面关键字与生命周期
               if (!lifecycle_Page.includes(key)) {
                 //判断组件 methods是否定义
                 if (!("methods" in config)) {
                   config.methods = {};
                 }
                 // 组件methods定义且为对象
                 // 合并方法
                 const { methods: cpt_methods } = config;
                 if (cpt_methods
                   && comUtils.isType(cpt_methods, "Object")
                   && cpt_methods[key] === undefined
                 ) {
                   cpt_methods[key] = mixin[key];
                 }
               }
             }
           }
         }
       })
     }
   })
 }
 
 